#include "common.h"
#include "client.h"

#include <vector>

bool 
TcpClient::init() {
    init_sockets();
    _socket = socket(AF_INET, SOCK_STREAM, 0);
    if (_socket == -1) {
        std::cout << "socket error" << std::endl;
        return false;
    }

    sockaddr_in addr;
    addr.sin_family = AF_INET;
    addr.sin_port = htons(_port);
    // addr.sin_addr.s_addr = inet_addr(_serverIP.c_str());
    inet_pton(AF_INET, _serverIP.c_str(), &addr.sin_addr); // Convert IP 
    if (-1 == connect(_socket, (sockaddr*)&addr, sizeof(addr))) {
        std::cerr << "Error connecting to server" << _serverIP << "(port "<< _port <<") : " 
                  << strerror(errno) << std::endl;
        close();
        return false;
    }

    std::cout << "Connected to server " << _serverIP << ":" << _port << std::endl;
    return true;
}
void
TcpClient::sendingMultiSmallMsg() {
    // --- Demonstrate sending multiple messages (potential for sticky packets) ---
    std::cout << "\n--- Sending multiple small messages quickly ---" << std::endl;
    sendMessage("Hello from client!");
    // std::this_thread::sleep_for(std::chrono::milliseconds(10)); // Short delay
    sendMessage("Another short message.");
    // std::this_thread::sleep_for(std::chrono::milliseconds(10)); // Short delay
    sendMessage("One more.");
    // std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Slightly longer delay
}

void
TcpClient::sendingOneBigMsg() {
    // --- Demonstrate sending a larger message (potential for split packets) ---
    std::cout << "\n---      ---" << std::endl;
    std::string large_message(2000, 'A'); // 2000 'A' characters
    large_message += " - This is a large message.";
    sendMessage( large_message);
    // std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
void
TcpClient::close() {
    close_socket(_socket);
    cleanup_sockets();
    _socket = -1;
}

void 
TcpClient::sendingMix() {
    std::cout << "\n--- Sending a mix of messages ---" << std::endl;
    sendMessage("Mix 1");
    std::string medium_message(500, 'B');
    sendMessage(medium_message);
    sendMessage("Mix 2");
    std::string short_message = "Short one.";
    sendMessage(short_message);
}


/**
 * @brief 发送TCP消息
 *
 * 将消息长度转换为网络字节序后，与消息内容一起发送到指定的socket。
 *
 * @param sockfd 目标socket文件描述符
 * @param message 要发送的消息内容
 * @return true 发送成功
 * @return false 发送失败或部分发送
 *
 * @note 消息格式为：4字节长度前缀(网络字节序) + 消息内容
 * @warning 目前部分发送会被视为失败，实际应用中需要处理部分发送情况
 */
bool TcpClient::sendMessage(const std::string &message)
{
    uint32_t message_length = message.length();
    uint32_t message_length_net = host_to_network(message_length);

    // Prepare data to send: length prefix + payload
    std::vector<char> data_to_send;
    data_to_send.resize(LENGTH_PREFIX_SIZE + message_length);

    // Copy length prefix
    std::memcpy(data_to_send.data(), &message_length_net, LENGTH_PREFIX_SIZE);

    // Copy message payload
    std::memcpy(data_to_send.data() + LENGTH_PREFIX_SIZE, message.data(), message_length);

    // Send the data
    ssize_t bytes_sent = send(_socket, data_to_send.data(), data_to_send.size(), 0);

    if (bytes_sent == -1) {
        std::cerr << "Error sending data: " << strerror(errno) << std::endl;
        return false;
    }
    if ((size_t)bytes_sent < data_to_send.size()) {
         std::cerr << "Warning: Only sent " << bytes_sent << " out of " << data_to_send.size() << " bytes for a message." << std::endl;
         // In a real app, you would need to handle partial sends and retry
         return false; // For this example, assume partial send is a failure
    }

    std::cout << "Sent message (" << message_length << " bytes): '" << message << "'" << std::endl;
    return true;
}
